﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HslCommunication.ModBus;
using HslCommunication;
using HslCommunication.BasicFramework;
using System.Net;
using System.Threading;
using System.Collections;
using System.Timers;
using HslCommunication.Controls;
using parkMonitor.entity;
using parkMonitor.tools;
using parkMonitor.model;
using System.Diagnostics;
using System.Configuration;
using parkMonitor.server.uiLogServer;
using parkMonitor.LOG;

namespace parkMonitor.server
{
    /// <summary>
    /// PLC通信类
    /// </summary>
    public class PLCLinker : IEquipments
    {
        private Boolean isConnection = false;
        private bool isRecorded = false, exceptionBreak = false, isClosing = false;
        private static string json = "";//读到的数据
        private string json2 = "";//写入的数据
        private PLCMessage plcMsg = new PLCMessage();
        System.Timers.Timer timer;
        //parameteres for plc read function
        private int startAddr = 0;
        private int addrLength = 110;
        /// <summary> plc重连标记位 </summary>
        private int linkCount = 0;
        //plc 基本配置
        private const short PLC_TIME_SCALE = 100;
        private const short LASER_TIME_SCALE = 5000;
        private string ipString;
        private int port;
        private byte station;
        //addresses for machine arm controlling
        private int fetching_startRobot_address;
        private int parking_startRobot_address;
        //addresses for laser data to be written to plc
        private int parkingSpaceID_address;
        //addresses for space info to be written to plc
        private int parkingLaserCenterX_address;
        //parameters(addresses) for Laser monitoring
        private int laser_start_address;
        private int fetch_completed_address;
        private int fetch_completed_acknowledge_address;
        private int fetch_to_address;
        private int frontWheelbase_address;
        private int rearWheelbase_address;
        private int park_completed_address;
        private int park_completed_acknowledge_address;
        private int LASER_RESCAN_COUNT;
        private int LASER_HEARTBEAT_PERIOD;
        private int PLC_refresh_interval;
        /// <summary>
        /// 激光管理list
        /// </summary>
        private List<LaserProcessUnit> laserMgmtList = new List<LaserProcessUnit>();
        private RobotProcessUnit rpu1;
        private List<string> decompressIndex;

        /// <summary>
        /// plc构造函数
        /// </summary>
        public PLCLinker()
        {
            try
            {
                LASER_RESCAN_COUNT = Int32.Parse(ConfigurationManager.AppSettings.Get("laser_rescan_count"));
                LASER_HEARTBEAT_PERIOD = Int32.Parse(ConfigurationManager.AppSettings.Get("laser_countdown"));
                PLC_refresh_interval = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_refresh_interval"));

                parking_startRobot_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parking_startRobot_address"));
                parkingLaserCenterX_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parkingLaserCenterX_address"));
                parkingSpaceID_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parkingSpaceID_address"));
                park_completed_address = Int32.Parse(ConfigurationManager.AppSettings.Get("park_completed_address"));
                park_completed_acknowledge_address = Int32.Parse(ConfigurationManager.AppSettings.Get("park_completed_acknowledge_address"));

                fetching_startRobot_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetching_startRobot_address"));
                fetch_to_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_to_address"));
                fetch_completed_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_completed_address"));
                fetch_completed_acknowledge_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_completed_acknowledge_address"));
                frontWheelbase_address = Int32.Parse(ConfigurationManager.AppSettings.Get("frontWheelbase_address"));
                rearWheelbase_address = Int32.Parse(ConfigurationManager.AppSettings.Get("rearWheelbase_address"));

                laser_start_address = Int32.Parse(ConfigurationManager.AppSettings.Get("laser_start_address"));

                rpu1 = new RobotProcessUnit(1, parking_startRobot_address, parkingLaserCenterX_address, parkingSpaceID_address, park_completed_address, park_completed_acknowledge_address, fetching_startRobot_address, fetch_to_address, fetch_completed_address, fetch_completed_acknowledge_address, frontWheelbase_address, rearWheelbase_address);

                //激光管理
                for (int i = 1; i < 20; i++)
                {
                    try
                    {
                        string laser = ConfigurationManager.AppSettings.Get("laser" + i + "_status_address");
                        int laser_status_address = Int32.Parse(laser);
                        LaserProcessUnit lpu = new LaserProcessUnit(i, laser_start_address, laser_status_address, LASER_RESCAN_COUNT, LASER_HEARTBEAT_PERIOD);
                        laserMgmtList.Add(lpu);
                        plcMsg.laserMsgList.Add(lpu.laserMsg);
                    }
                    catch (Exception) { }
                }

                //定义plc被压缩的地址段
                decompressIndex = new List<string>();
                //25-27
                for (int i = 0; i < 3; i++)
                {
                    decompressIndex.Add((25 + i).ToString());
                }
                //48-53
                for (int i = 0; i < 6; i++)
                {
                    decompressIndex.Add((48 + i).ToString());
                }
                //70-76
                for (int i = 0; i < 7; i++)
                {
                    decompressIndex.Add((70 + i).ToString());
                }
            }
            catch (Exception)
            {
                Console.WriteLine("PLC相关配置文件异常");
            }
        }

        //**************************************** PLC读写相关方法 **************************************
        private ModBusTcpClient busTcpClient
        {
            get;
            set;
        }

        private void WriteMessage(string message)
        {
            isRecorded = true;
            //json2 = "[{\"Adress\":\"1\",\"Value\":\"0043\"},{\"Adress\":\"2\",\"Value\":\"0043\"}]";
            json2 = message;
        }

        ///<summary>采集数据显示转json</summary>
        private static void DisplayString_ToJson(string str)
        {
            List<PLCNode> return_Value = new List<PLCNode>();
            if (!string.IsNullOrEmpty(str))
            {
                ArrayList array = GetSeparateSubString(str, 4);
                int Read_Address = 0;//0地址
                return_Value.Clear();
                foreach (string arr in array)
                {
                    PLCNode rv = new PLCNode();
                    //Console.WriteLine("地址:" + Read_Address + ": " + arr);
                    rv.Address = Read_Address.ToString();
                    rv.Value = Int32.Parse(arr, System.Globalization.NumberStyles.HexNumber).ToString();//plc数据16进制？
                    return_Value.Add(rv);
                    Read_Address++;
                }
            }
            json = JsonHelper.SerializeObject(return_Value);//序列化     
            //List<PLCValue> prv = JsonHelper.DeserializeJsonToList<PLCValue>(json);

            //Console.WriteLine(json);
        }

        ///<summary>截取</summary>
        private static ArrayList GetSeparateSubString(string txtString, int charNumber)
        {
            ArrayList arrList = new ArrayList();
            string tempStr = txtString;
            for (int i = 0; i < tempStr.Length; i += charNumber)
            {
                if ((tempStr.Length - i) > charNumber)
                {
                    arrList.Add(tempStr.Substring(i, charNumber));
                }
                else
                {
                    arrList.Add(tempStr.Substring(i));
                }
            }
            return arrList;
        }

        private void InitTimer()
        {
            try
            {
                timer = new System.Timers.Timer(PLC_refresh_interval);
            }
            catch (Exception)
            {
                timer = new System.Timers.Timer(PLC_TIME_SCALE);
            }

            timer.AutoReset = true;
            timer.Enabled = true;
            timer.Elapsed += new ElapsedEventHandler(TimerUp);
        }

        ///<summary>实时采集</summary>
        private void TimerUp(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                if (isConnection)
                {
                    //从哪个地址开始,读取长度
                    PLC_Read((ushort)startAddr, (ushort)addrLength);
                    //LaserMonitor();
                }
                else
                {
                    if (linkCount-- >= 0)
                    {
                        Task.Factory.StartNew(() =>
                        {
                            while (!isClosing)
                            {
                                Console.WriteLine("尝试重连plc");
                                UILogServer.ins.log("尝试重连plc");
                                LinkStart();
                                Thread.Sleep(10000);
                                if (isConnection)
                                {
                                    linkCount = 0;
                                    break;
                                }
                            }
                        });
                        linkCount = -1;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        ///<summary>读取</summary>
        private void PLC_Read(ushort address, ushort length)
        {
            try
            {
                OperateResult<byte[]> read = busTcpClient.ReadRegister(address, length);
                if (read.IsSuccess)
                {
                    string returned_value = SoftBasic.ByteToHexString(read.Content);
                    DisplayString_ToJson(returned_value);
                }
                else
                {
                    if (!exceptionBreak)
                    {
                        AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
                        Console.WriteLine("读取失败");
                        isConnection = false;
                        exceptionBreak = true;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        ///<summary>写入</summary>
        private void WriteJson(string json)
        {
            try
            {
                if (!string.IsNullOrEmpty(json))
                {
                    List<PLCNode> PLC_Value = JsonHelper.DeserializeJsonToList<PLCNode>(json);
                    foreach (var item in PLC_Value)
                    {
                        //WriteResultRender(busTcpClient.WriteRegister(ushort.Parse(item.Address), ushort.Parse(item.Value)), item.Address);
                        busTcpClient.WriteRegister(ushort.Parse(item.Address), ushort.Parse(item.Value));
                        Thread.Sleep(20);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        ///<summary>写入判断</summary>
        private static void WriteResultRender(OperateResult result, string address)
        {
            if (result.IsSuccess)
            {
                Console.WriteLine("写入成功");
            }
            else
            {
                Console.WriteLine("写入失败");
            }
        }

        ///<summary>地址-值写入plc</summary>
        private void SendtoPLC(string addr, string value)
        {
            PLCNode wrv = new PLCNode();
            wrv.Address = addr;
            wrv.Value = value;
            json2 = "[" + JsonHelper.SerializeObject(wrv) + "]";
            WriteMessage(json2);
            if (isConnection && isRecorded)
            {
                WriteJson(json2);
                isRecorded = false;
            }
        }

        /// <summary>启动与plc的连接</summary>
        private void LinkStart()
        {
            if (busTcpClient != null)
            {
                busTcpClient.ConnectClose();
            }
            busTcpClient = new ModBusTcpClient(ipString, port, station);
            try
            {
                OperateResult connect = busTcpClient.ConnectServer();
                if (connect.IsSuccess)
                {
                    AsyncCmdServer.ins.send(AsyncCmdType.PLCOnline);
                    Console.WriteLine("连接成功");
                    UILogServer.ins.log("PLC连接成功");
                    isConnection = true;
                    linkCount = 0;
                }
                else
                {
                    AsyncCmdServer.ins.send(AsyncCmdType.PLCOffline);
                    Console.WriteLine("连接失败，重试");
                    UILogServer.ins.error("PLC连接失败，重试");
                    isConnection = false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            InitTimer();//启动计时器
        }

        /// <summary>将plc地址块完全解压</summary>
        private List<PLCNode> ListDecompression(List<PLCNode> plcList, List<string> decompressIndex)
        {
            List<string> temp = new List<string>();
            List<PLCNode> decomPlcList = new List<PLCNode>();
            if (plcList != null && addrLength > 100)
            {
                try
                {
                    for (int i = 0; i < plcList.Count; i++)
                    {
                        if (!decompressIndex.Contains(plcList[i].Address))
                        {
                            temp.Add(plcList[i].Value);
                        }
                        //定位三个被压缩区域
                        else
                        {
                            //默认LSB优先
                            int value = Int32.Parse(plcList[i].Value);
                            int count = 16;
                            while (count-- > 0)
                            {
                                temp.Add((value & 0x01).ToString());
                                value = value >> 1;
                            }
                        }
                    }
                }
                catch (Exception) { }
            }
            for (int i = 0; i < temp.Count; i++)
            {
                decomPlcList.Add(new PLCNode(i.ToString(), temp[i]));
            }
            return decomPlcList;
        }
        //************************************ 雷达相关方法 **************************************
        /*
         * 激光监听PARK_STATUS, 0等待，1启动，其余异常
         * PARK_STATUS 控制：
         * 核心线程调用SetMessage将其置1，plc线程检测到PARK_COMPLETED则复位到0，(核心将plc“PARK_COMPLETED”复位)，其余异常情况由监控或核心线程置2或其他值
         * 
         * 读到LASER_STATUS（扫摆激光状态），监控线程显示该状态，一旦为状态5，处理完成后置0
         * 
         * */
        private void LaserMonitor()
        {
            try
            {
                if (plcMsg.originalPlcList != null)
                {
                    foreach (LaserProcessUnit lds in laserMgmtList)
                    {
                        foreach (PLCNode p in plcMsg.originalPlcList)
                        {
                            int addr = Int32.Parse(p.Address);
                            int value = Int32.Parse(p.Value);
                            lds.LaserStatusChecking(addr, value);
                        }
                        lds.LaserRecord(plcMsg.originalPlcList);
                    }
                }
                else
                {
                    AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
                    return;
                }
                Thread.Sleep(200);
            }
            catch (Exception)
            {
                AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
                return;
            }
        }
        private void UpdateLaserStatus()
        {
            try
            {
                lock (plcMsg)
                {
                    if (plcMsg.originalPlcList != null)
                    {
                        foreach (LaserProcessUnit lds in laserMgmtList)
                        {
                            foreach (PLCNode p in plcMsg.originalPlcList)
                            {
                                int addr = Int32.Parse(p.Address);
                                int value = Int32.Parse(p.Value);
                                lds.UpdateLaserStatus(addr, value);
                            }
                        }
                    }
                    else
                    {
                        AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
                        return;
                    }
                }
            }
            catch (Exception)
            {
                AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
                return;
            }
        }
        private void WaitForLaserReady(LaserProcessUnit lpuTemp)
        {
            bool jumpOut = false;
            MyTimer mt = new MyTimer();
            mt.StartTiming();
            lock (lpuTemp)
            {
                while (!jumpOut)
                {
                    Thread.Sleep(1000);
                    if (plcMsg != null && plcMsg.originalPlcList.Count > lpuTemp.laser_status_address)
                    {
                        foreach (PLCNode node in plcMsg.originalPlcList)
                        {
                            //判断激光空闲状态
                            if (node.Address.Equals(lpuTemp.laser_status_address.ToString()) && (node.Value.Equals("254") || node.Value.Equals("255")) && !lpuTemp.laserMsg.occupied)
                            {
                                lpuTemp.laserMsg.occupied = true;
                                jumpOut = true;
                                UILogServer.ins.log("获取摆扫激光空闲状态，准备启动激光");
                                break;
                            }
                        }
                    }
                    mt.EndTiming();
                    int activationCount = 0;
                    if (mt.IsLonger(15, 1, false, out activationCount))
                    {
                        if (activationCount == 1)
                        {
                            UILogServer.ins.info("启动前暂未获取摆扫激光空闲状态，继续等待");
                        }
                        if (MyTimer.restart && !mt.rolledBack)
                        {
                            mt.rolledBack = true;
                            UILogServer.ins.error("启动前超时未能获取摆扫激光心跳，请检查设备");
                        }
                    }
                }
            }
        }

        //***************公有方法****************
        /// <summary>
        /// 获取plc数据与激光数据
        /// </summary>
        /// <returns>返回plc消息实例</returns>
        public AbstractMessage GetMessage()
        {
            try
            {
                plcMsg.originalPlcList = JsonHelper.DeserializeJsonToList<PLCNode>(json);
                if (decompressIndex != null && decompressIndex.Count != 0)
                {
                    plcMsg.extendedPlcList = ListDecompression(plcMsg.originalPlcList, decompressIndex);
                }
                return (PLCMessage)plcMsg.Clone();
            }
            catch (Exception)
            {
                AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
                return new PLCMessage();
            }
        }

        /// <summary>
        /// 传入信息写入plc
        /// </summary>
        /// <param name="message">plc消息则传入plc，控制消息则根据指令编号分别处理</param>
        public void SetMessage(AbstractMessage message)
        {
            if (message.GetType().Equals(typeof(PLCMessage)))
            {
                PLCMessage ps = (PLCMessage)message;
                for (int i = 0; i < ps.originalPlcList.Count; i++)
                {
                    SendtoPLC(ps.originalPlcList[i].Address, ps.originalPlcList[i].Value);
                }
            }
            else if (message.GetType().Equals(typeof(PLCNode)))
            {
                PLCNode pv = (PLCNode)message;
                SendtoPLC(pv.Address, pv.Value);
            }
            else if (message.GetType().Equals(typeof(ControlMessage)))
            {
                ControlMessage cm = (ControlMessage)message;
                if (cm != null && cm.status != 0)
                {
                    switch (cm.status)
                    {
                        //停车startLaser--park_command_address
                        case 1:
                            //start laser scanning for parking
                            LaserProcessUnit lpuTemp = null;
                            Task.Factory.StartNew(() =>
                            {
                                string laser_start_addr = "";
                                foreach (LaserProcessUnit lpu in laserMgmtList)
                                {
                                    if (cm.laserID == lpu.id)
                                    {
                                        lpuTemp = lpu;
                                        laser_start_addr = lpu.laser_start_address.ToString();
                                        break;
                                    }
                                }
                                if (laser_start_addr == "")
                                    return;
                                lock (lpuTemp)
                                {
                                    WaitForLaserReady(lpuTemp);
                                    SendtoPLC(laser_start_addr, "0");
                                    lpuTemp.laserMsg.licenseNum = cm.LicenseNum;
                                    Thread.Sleep(300);
                                    SendtoPLC(laser_start_addr, "1");
                                    Thread.Sleep(100);
                                    SendtoPLC("1", "1");//停车指令置1
                                    Log.WriteLog("已发送激光" + lpuTemp.id + "启动指令");
                                    UILogServer.ins.info("已发送激光" + lpuTemp.id + "启动指令");
                                }
                            });
                            //Console.WriteLine("扫摆激光启动");
                            break;
                        //停车激光的6个数据,停车机械手,车位信息4个
                        case 2:
                            if (cm.RobotID == 1)
                            {
                                //停车启动机械手
                                SendtoPLC(rpu1.parking_startRobot_address.ToString(), "1");
                                //自动或手动输入激光雷达数据
                                SendtoPLC(rpu1.parking_laserCenterX_address.ToString(), cm.centerX);
                                SendtoPLC((rpu1.parking_laserCenterX_address + 1).ToString(), cm.centerY);
                                SendtoPLC((rpu1.parking_laserCenterX_address + 2).ToString(), cm.angleA);
                                //车位信息
                                SendtoPLC(rpu1.parkingSpaceID_address.ToString(), cm.parkingSpaceID);
                                SendtoPLC((rpu1.parkingSpaceID_address + 1).ToString(), cm.parkingSpaceX);
                                SendtoPLC((rpu1.parkingSpaceID_address + 2).ToString(), cm.parkingSpaceY);
                                SendtoPLC((rpu1.parkingSpaceID_address + 3).ToString(), cm.parkingSpaceZ);
                            }
                            break;
                        //停车完成归零--park_completed_address
                        case 3:
                            if (cm.RobotID == 1)
                            {
                                //SendtoPLC(rpu1.park_completed_address.ToString(), "0");//停车完成复位
                                SendtoPLC(rpu1.park_completed_acknowledge_address.ToString(), "0");
                                SendtoPLC("1", "0");//停车指令置0
                                //Console.WriteLine("停车完成");
                            }
                            break;
                        //取车机械手,车位信息4个
                        case 4:
                            if (cm.RobotID == 1 && cm.fetchPosition != 0)
                            {
                                //前后轮轮距
                                SendtoPLC(rpu1.frontWheelbase.ToString(), cm.frontWheelbase.ToString());
                                SendtoPLC(rpu1.rearWheelbase.ToString(), cm.rearWheelbase.ToString());
                                //取至区域
                                //SendtoPLC(rpu1.fetch_to_address.ToString(), pm.fetchPosition.ToString());
                                SendtoPLC(rpu1.fetch_to_address.ToString(), cm.parkingSpaceX);
                                //车位信息
                                SendtoPLC(rpu1.parkingSpaceID_address.ToString(), cm.parkingSpaceID);
                                SendtoPLC((rpu1.parkingSpaceID_address + 1).ToString(), cm.parkingSpaceX);
                                SendtoPLC((rpu1.parkingSpaceID_address + 2).ToString(), cm.parkingSpaceY);
                                SendtoPLC((rpu1.parkingSpaceID_address + 3).ToString(), cm.parkingSpaceZ);
                                SendtoPLC(rpu1.fetching_startRobot_address.ToString(), "1");
                            }
                            break;
                        case 5:
                            if (cm.RobotID == 1)
                            {
                                //取车完成复位
                                SendtoPLC(rpu1.fetch_completed_acknowledge_address.ToString(), "0");
                                SendtoPLC(rpu1.fetch_to_address.ToString(), "0");
                            }
                            break;
                        default: Console.WriteLine("输入plc数据异常"); break;
                    }
                }
            }
            else
            {
                AsyncCmdServer.ins.send(AsyncCmdType.PLCWriteException);
                Debug.WriteLine("输入字符串有误");
            }
        }

        /// <summary>
        /// 开启激光线程与模拟plc自动重置子线程
        /// </summary>
        public void Start()
        {
            exceptionBreak = false; linkCount = 0;
            try
            {
                ipString = ConfigurationManager.AppSettings.Get("PLC_ip_address");
                port = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_port"));
                station = (byte)Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_station"));
                startAddr = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_start_address"));
                addrLength = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_address_length"));
            }
            catch (Exception) { UILogServer.ins.error("PLC配置文件异常"); }
            LinkStart();

            Task.Factory.StartNew(() =>
            {
                while (!isClosing)
                {
                    LaserMonitor();
                }
            });
            Task.Factory.StartNew(() =>
            {
                while (!isClosing)
                {
                    UpdateLaserStatus();
                }
            });
            //模拟plc与激光自动操作
            Task.Factory.StartNew(() =>
            {
                laserAnim();
            });
            Task.Factory.StartNew(() =>
            {
                wheelbaseAnim();
            });
            Task.Factory.StartNew(() =>
            {
                autoCycling();
            });
        }

        /// <summary>
        /// 系统停止
        /// </summary>
        public void Stop()
        {
            exceptionBreak = false; isClosing = true;
            busTcpClient.ConnectClose();//stop释放资源
            //throw new NotImplementedException();
        }

        private void laserAnim()
        {
            bool laserWorking = false;
            while (!isClosing)
            {
                //模拟plc与激光操作
                foreach (PLCNode p in plcMsg.originalPlcList)
                {
                    int addr = Int32.Parse(p.Address);
                    int value = Int32.Parse(p.Value);
                    //模拟摆扫激光
                    if (laserMgmtList.Count != 0)
                    {
                        if (addr == laser_start_address)
                        {
                            //心跳
                            if (value == 0)
                            {
                                laserWorking = false;
                                SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "254");
                                Thread.Sleep(1000);
                                SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "255");
                                Thread.Sleep(1000);
                            }
                            //模拟测量
                            else
                            {
                                if (!laserWorking)
                                {
                                    SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "1");
                                    Thread.Sleep(500);
                                    SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "2");
                                    Thread.Sleep(5000);
                                    SendtoPLC((laserMgmtList[0].laser_status_address + 1).ToString(), (new Random(DateTime.Now.Millisecond).Next(4000, 7000)).ToString());
                                    Thread.Sleep(1);
                                    SendtoPLC((laserMgmtList[0].laser_status_address + 2).ToString(), (new Random(DateTime.Now.Millisecond).Next(4000, 7000)).ToString());
                                    Thread.Sleep(1);
                                    SendtoPLC((laserMgmtList[0].laser_status_address + 3).ToString(), (new Random(DateTime.Now.Millisecond).Next(90, 150)).ToString());
                                    Thread.Sleep(1);
                                    SendtoPLC(laserMgmtList[0].laser_status_address.ToString(), "3");
                                    Thread.Sleep(2000);
                                }
                                laserWorking = true;
                            }
                        }
                    }
                }
                Thread.Sleep(200);
            }
        }
        private void wheelbaseAnim()
        {
            bool working = false;
            while (!isClosing)
            {
                //模拟plc与激光操作
                foreach (PLCNode p in plcMsg.originalPlcList)
                {
                    int addr = Int32.Parse(p.Address);
                    int value = Int32.Parse(p.Value);
                    //模拟轮距激光
                    if (addr == parking_startRobot_address)
                    {
                        if (value == 1)
                        {
                            if (!working)
                            {
                                working = true;
                                Thread.Sleep(3000);
                                SendtoPLC(frontWheelbase_address.ToString(), (new Random(DateTime.Now.Millisecond).Next(100, 300)).ToString());
                                Thread.Sleep(1);
                                SendtoPLC(rearWheelbase_address.ToString(), (new Random(DateTime.Now.Millisecond).Next(100, 300)).ToString());
                                SendtoPLC("81", "3");
                                Thread.Sleep(5000);
                            }
                        }
                        else
                        {
                            working = false;
                            SendtoPLC("81", "254");
                            Thread.Sleep(1000);
                            SendtoPLC("81", "255");
                            Thread.Sleep(1000);
                        }
                    }
                }
                Thread.Sleep(200);
            }
        }
        private void autoCycling()
        {
            while (!isClosing)
            {
                //模拟plc与激光操作
                foreach (PLCNode p in plcMsg.originalPlcList)
                {
                    int addr = Int32.Parse(p.Address);
                    int value = Int32.Parse(p.Value);
                    //停取车复位
                    if (addr == park_completed_acknowledge_address && value == 0)
                    {
                        Thread.Sleep(2000);
                        SendtoPLC(park_completed_address.ToString(), "0");
                        SendtoPLC(park_completed_acknowledge_address.ToString(), "1");
                    }
                    if (addr == fetch_completed_acknowledge_address && value == 0)
                    {
                        Thread.Sleep(2000);
                        SendtoPLC(fetch_completed_address.ToString(), "0");
                        SendtoPLC(fetch_completed_acknowledge_address.ToString(), "1");
                    }
                    //停车完成
                    if (addr == parking_startRobot_address && value == 1)
                    {
                        Thread.Sleep(10000);
                        SendtoPLC(park_completed_address.ToString(), "1");
                        SendtoPLC(addr.ToString(), "0");
                    }
                    //取车完成
                    if (addr == fetching_startRobot_address && value == 1)
                    {
                        Thread.Sleep(10000);
                        SendtoPLC(fetch_completed_address.ToString(), "1");
                        SendtoPLC(addr.ToString(), "0");
                    }
                }
                Thread.Sleep(200);
            }
        }
    }

    /// <summary>
    /// 激光数据记录与处理类
    /// </summary>
    class LaserProcessUnit
    {
        public int laser_start_address { get; set; }
        public int laser_status_address { get; set; }
        public int id { get; set; }
        private int LASER_RESCAN_COUNT, LASER_HEARTBEAT_PERIOD, laser_rescan_countdown, laser_heartbeat_countdown;
        private bool laser_record, laser_heartbeat_test, enable_status_check = true, disconnected = false;
        private HashSet<int> laser_heartbeat = new HashSet<int>();
        private IEquipments plc = null;
        public LaserMessage laserMsg = new LaserMessage();

        public LaserProcessUnit(int id, int park_command_address, int laser_status_address, int laser_rescan_count, int laser_heartbeat_period)
        {
            try
            {
                laserMsg.id = id;
                this.id = id;
                laserMsg.status = 6;
                this.laser_start_address = park_command_address;
                this.laser_status_address = laser_status_address;
                LASER_RESCAN_COUNT = laser_rescan_count;
                LASER_HEARTBEAT_PERIOD = laser_heartbeat_period;
                laser_rescan_countdown = LASER_RESCAN_COUNT;
                laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
                plc = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC);
            }
            catch (Exception)
            {
                UILogServer.ins.error("激光设备配置文件错误");
            }
        }
        /// <summary>
        /// 更新激光状态
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="value"></param>
        public void UpdateLaserStatus(int addr, int value)
        {
            if (enable_status_check)
            {
                int status_addr = laser_status_address;
                if (addr == status_addr)
                {
                    if (!disconnected)
                    {
                        laserMsg.status = value;
                        //UILogServer.ins.log(value.ToString());
                    }
                }
            }
        }
        ///<summary>激光状态监测</summary>
        public void LaserStatusChecking(int addr, int value)
        {
            if (enable_status_check)
            {
                int status_addr = laser_status_address;
                if (addr == status_addr)
                {
                    //after status 0, start to check laser heartbeat
                    if (value == 0)
                    {
                        laserMsg.abort_rescan = false;//就绪状态设置允许重测
                        laser_heartbeat_test = true;
                    }
                    //after status 3 or 4, start to check laser heartbeat
                    if (value == 3 && !laserMsg.recorded && laserMsg.licenseNum != "")
                    {
                        if (plc == null)
                        {
                            plc = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC);
                        }
                        if (plc != null)
                        {
                            PLCNode pn = new PLCNode(laser_start_address.ToString(), "0");
                            plc.SetMessage(pn);
                            //停车指令置0
                            MyTimer mt = new MyTimer();
                            mt.StartTiming();
                            while (laserMsg.status != 254 && laserMsg.status != 255)
                            {
                                Thread.Sleep(1000);
                                mt.EndTiming();
                                int activationCount = 0;
                                if (mt.IsLonger(15, 1, false, out activationCount))
                                {
                                    if (activationCount == 1)
                                    {
                                        UILogServer.ins.info("记录数据前未获得心跳，继续等待");
                                    }
                                    if (MyTimer.restart && !mt.rolledBack)
                                    {
                                        mt.rolledBack = true;
                                        UILogServer.ins.error("记录数据前超时未获得心跳，请检查设备");
                                    }
                                }
                            }
                            laser_record = true;
                            laser_rescan_countdown = LASER_RESCAN_COUNT;
                            laser_heartbeat_test = true;
                        }
                    }

                    else if (value == 4)
                    {
                        laser_record = false;
                        //启动重测指令
                        if (laser_rescan_countdown > 0)
                        {
                            enable_status_check = false;
                            Task t = Task.Factory.StartNew(() =>
                            {
                                Thread.Sleep(500);
                                if (plc == null)
                                {
                                    plc = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC);
                                }
                                if (plc != null)
                                {
                                    lock (laserMsg)
                                    {
                                        laser_rescan_countdown--;
                                        //停车指令置0
                                        PLCNode pn = new PLCNode(laser_start_address.ToString(), "0");
                                        plc.SetMessage(pn);
                                        //未终止重测，车未开走，停车指令归零后置1
                                        if (!laserMsg.abort_rescan)
                                        {
                                            UILogServer.ins.error("激光" + laserMsg.id + "计算异常，重新测量");
                                            //重测检测心跳
                                            Task rescan_wait_heartbeat = Task.Factory.StartNew(() =>
                                            {
                                                MyTimer mt = new MyTimer();
                                                mt.StartTiming();
                                                while (laserMsg.status != 254 && laserMsg.status != 255)
                                                {
                                                    Thread.Sleep(1000);
                                                    mt.EndTiming();
                                                    int activationCount = 0;
                                                    if (mt.IsLonger(15, 1, false, out activationCount))
                                                    {
                                                        if (activationCount == 1)
                                                        {
                                                            UILogServer.ins.info("重测前未获得心跳，继续等待");
                                                        }
                                                        if (MyTimer.restart && !mt.rolledBack)
                                                        {
                                                            mt.rolledBack = true;
                                                            UILogServer.ins.error("发起重测前超时未能获取摆扫激光心跳，请检查设备");
                                                        }
                                                    }
                                                }
                                            });
                                            UILogServer.ins.log("获得心跳，准备发起重测");
                                            rescan_wait_heartbeat.Wait();
                                            pn = new PLCNode(laser_start_address.ToString(), "1");
                                            plc.SetMessage(pn);
                                            laserMsg.status = value;
                                        }
                                        else
                                        {
                                            laserMsg.status = 6;
                                        }
                                    }
                                    Thread.Sleep(500);
                                }
                                enable_status_check = true;
                            });
                        }
                        else if (laser_rescan_countdown == 0)
                        {
                            //激光1异常
                            laser_rescan_countdown = -1;
                            laser_heartbeat_test = false;
                            UILogServer.ins.error("激光" + laserMsg.id + "计算异常超过重测次数，请检查");
                        }
                    }

                    //status 5, system error
                    if (value == 5)
                    {
                        lock (laserMsg)
                        {
                            laser_heartbeat_test = false;
                            UILogServer.ins.error("激光系统异常，请检查");
                        }
                    }

                    //find the heartbeat of laser
                    if (laser_heartbeat_test && laser_heartbeat_countdown-- > 0 && value != 3 && value != 4)
                    {
                        if (value == 254 || value == 255)
                            laser_heartbeat.Add(value);
                        if (laser_heartbeat.Contains(254) && laser_heartbeat.Contains(255))
                        {
                            disconnected = false;
                            laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
                            laser_heartbeat_test = false;
                            Console.WriteLine("激光" + laserMsg.id + "已检测到心跳");
                            laser_heartbeat.Clear();
                        }
                        //fail to check laser heartbeat
                        if (laser_heartbeat_countdown <= 0)
                        {
                            laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
                            lock (laserMsg)
                            {
                                if (laserMsg.status >= 0)
                                {
                                    UILogServer.ins.error("激光" + laserMsg.id + "心跳检测失败");
                                }
                                disconnected = true;
                                laserMsg.status = -1;
                            }
                        }
                    }
                }
            }
            else { return; }
        }

        /// <summary>激光数据记录</summary>
        public void LaserRecord(List<PLCNode> plist)
        {
            lock (laserMsg)
            {
                //激光未掉线，记录数据写入plc
                if (laserMsg.status != -1)
                {
                    if (laser_record)
                    {
                        laser_record = false;
                        foreach (PLCNode p in plist)
                        {
                            int addr = Int32.Parse(p.Address);
                            int value = Int32.Parse(p.Value);
                            if (addr == laser_status_address + 1)
                                laserMsg.data.centerX = value;
                            else if (addr == laser_status_address + 2)
                                laserMsg.data.centerY = value;
                            else if (addr == laser_status_address + 3)
                                laserMsg.data.angleA = value;
                            else if (addr == laser_status_address + 4)
                                laserMsg.data.length = value;
                            else if (addr == laser_status_address + 5)
                                laserMsg.data.width = value;
                            else if (addr == laser_status_address + 6)
                                laserMsg.data.height = value;
                        }
                        laserMsg.recorded = true;
                        UILogServer.ins.info("摆扫激光测量数据已记录");
                    }
                }
            }
        }
    }

    /// <summary>
    /// 机械手逻辑处理类
    /// </summary>
    class RobotProcessUnit
    {
        public int id { get; set; }
        public int parking_startRobot_address { get; set; }
        public int parking_laserCenterX_address { get; set; }
        public int parkingSpaceID_address { get; set; }
        public int park_completed_address { get; set; }
        public int park_completed_acknowledge_address { get; set; }
        public int fetching_startRobot_address { get; set; }
        public int fetch_completed_address { get; set; }
        public int fetch_completed_acknowledge_address { get; set; }
        public int fetch_to_address { get; set; }
        public int frontWheelbase { get; set; }
        public int rearWheelbase { get; set; }

        public RobotProcessUnit(int id, int parking_startRobot_address, int parking_laserCenterX_address, int parkingSpaceID_address, int park_completed_address, int park_completed_acknowledge_address, int fetching_startRobot_address, int fetch_to_address, int fetch_completed_address, int fetch_completed_acknowledge_address, int frontWheelbase, int rearWheelbase)
        {
            this.id = id;
            this.parking_startRobot_address = parking_startRobot_address;
            this.parking_laserCenterX_address = parking_laserCenterX_address;
            this.parkingSpaceID_address = parkingSpaceID_address;
            this.park_completed_address = park_completed_address;
            this.park_completed_acknowledge_address = park_completed_acknowledge_address;
            this.fetching_startRobot_address = fetching_startRobot_address;
            this.fetch_completed_address = fetch_completed_address;
            this.fetch_completed_acknowledge_address = fetch_completed_acknowledge_address;
            this.fetch_to_address = fetch_to_address;
            this.frontWheelbase = frontWheelbase;
            this.rearWheelbase = rearWheelbase;
        }
    }
}
